package com.fucking.great.context.util;

import cn.hutool.core.util.ClassUtil;
import cn.hutool.core.util.StrUtil;
import com.fucking.great.context.single.SingleFactory;

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;

/**
 * 单例bean工具.
 */
public abstract class SingleUtil {
    private SingleUtil(){}

    private final static Map<String,Object> SINGLE_MAP = new ConcurrentHashMap<>();

    static{
        ServiceLoader<SingleFactory> peoples = ServiceLoader.load(SingleFactory.class);
        Iterator<SingleFactory> iterator = peoples.iterator();
        while (iterator.hasNext()) {
            SingleFactory singleFactory = iterator.next();
            //
            Map<String, Object> needRegsigAllBean = singleFactory.getNeedRegsigAllBean(SINGLE_MAP);
            for (Map.Entry<String, Object> stringObjectEntry : needRegsigAllBean.entrySet()) {
                // 调用注册。
                regsigBean(stringObjectEntry.getKey(),stringObjectEntry.getValue());
            }
        }
    }

    /**
     * 是否注册成功，如果存在会报错。
     * @param key
     * @param bean
     *
     */
    public static void regsigBean(String key,Object bean){
        if (Objects.isNull(bean)) {
            throw new ExceptionInInitializerError(StrUtil.format("BeanName=[{}] hava to not null", key ));
        }
        if (SINGLE_MAP.putIfAbsent(key, bean) != null) {
            throw new ExceptionInInitializerError(StrUtil.format("BeanName=[{}],current bean=[{}] exist , please pom or jar for plugFactory ", key ,bean.getClass()));
        }
//        return SINGLE_MAP.putIfAbsent(key, bean) == null;
    }

    public static Object getBean(String key){
        return SINGLE_MAP.get(key);
    }
    public static <T> T getBean(Class<T> type){
        return (T) SINGLE_MAP.get(classToKey(type));
    }

    /**
     * 规范，把类型转化单例缓存池中key的标准。
     * @param type
     * @return
     */
    public static String classToKey(Class<?> type){
        return type.getName();
    }

    /**
     * 如果key，不存在则调用mappingFunction的方法new出来。
     * 存在则不调用。
     * @param key
     * @param mappingFunction
     * @return
     */
    public static Object getBean(String key, Function<String, Object> mappingFunction){
        return SINGLE_MAP.computeIfAbsent(key,mappingFunction);
    }

    /**
     * 1. 获得某个接口所有的实现类对应的单例。
     * 2. 获得某个父类下所有的实现类对应的单例。
     * @return
     */
    public static <T> List<T> getAllImpBean(Class<T> interfaceClass){
        List<T> list = new ArrayList<>();
        SINGLE_MAP.values().forEach(x -> {
            if (ClassUtil.isAssignable(interfaceClass,x.getClass())) {
                list.add((T) x);
            }
        });
        return list;
    }



}
